package com.yz.promotion.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yz.common.factory.JedisFactory;
import com.yz.promotion.mapping.PromotionMapping;
import com.yz.model.vo.LoginUserVo;
import com.yz.model.vo.promotion.PromotionVo;
import com.yz.common.constant.Constants;
import com.yz.common.constant.PromotionConstant;
import com.yz.promotion.mapper.PromotionMapper;
import com.yz.model.entity.promotion.PromotionCode;
import com.yz.promotion.properties.DiscountRateProperties;
import com.yz.promotion.service.PromotionService;
import com.yz.promotion.service.feign.PromotionUserFeign;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.util.Date;
import java.util.List;
import java.util.Random;

import static com.yz.common.utils.PromotionCodeUtils.*;

/**
 * Created With IntelliJ IDEA.
 * Descriptions:
 * <p>
 * User:Mr.Du
 * Date:2024/3/25
 * Time:16:40
 */
@Slf4j
@Service
public class PromotionServiceImpl extends ServiceImpl<PromotionMapper, PromotionCode> implements PromotionService {

    @Resource
    private PromotionMapping promotionMapping;

    @Resource
    private PromotionUserFeign promotionUserFeign;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private DiscountRateProperties discountRateProperties;

    @Resource
    private JedisFactory jedisFactory;


    @Override
    public void createPromotionCode(Long uid) {
        try {
            LoginUserVo user = promotionUserFeign.getUserById(uid);
            log.info("user", user);
            if(user == null){
                throw new RuntimeException("用户不存在");
            }
            // 校验优惠码数量
            int count = user.getCountPromotion();
            if(count == 0){
                throw new RuntimeException("优惠码已经达到上限");
            }
            generatePromotionCode(uid, count);
            // 更新用户信息
            promotionUserFeign.updateUserCountPromotion(uid, 0);
            log.info("生成优惠码成功");
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }

    }

    @Override
    public PromotionVo checkPromotionCode(Long uid, String codes) {
        log.info("uid: {}, codes: {}", uid, codes);
        if(codes == null || codes.length() != 49 || (codes.charAt(codes.length() - 1) != '0' && codes.charAt(codes.length() - 1) != '1')){
            throw new RuntimeException("优惠码格式错误");
        }
//        Jedis jedis = jedisFactory.getJedis();
//        System.out.println(jedis.get(PromotionConstant.PROMOTION_CODE_PREFIX + uid + codes));
//        // 校验优惠码是否已使用
//        if(StringUtils.isNotEmpty(jedis.get(PromotionConstant.PROMOTION_CODE_PREFIX + uid + codes))){
//            throw new RuntimeException("优惠码不可用");
//        }
        String[] promotionInfo = getPromotionInfo(codes);
        String code = promotionInfo[0];
        String token = promotionInfo[1];
        Integer type = Integer.valueOf(promotionInfo[2]);
        QueryWrapper<PromotionCode> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("code", code);
        queryWrapper.eq("token", token);
        queryWrapper.eq("type", type);
        if(type == 1){
            queryWrapper.eq("uid", uid);
        }
        PromotionCode promotionCode = baseMapper.selectOne(queryWrapper);
        if(promotionCode == null){
            throw new RuntimeException("优惠码不存在");
        }else if(promotionCode.getStatus() == 1){
            throw new RuntimeException("优惠码已使用");
        }else if(promotionCode.getStatus() == 2){
            throw new RuntimeException("优惠码已过期");
        }
        promotionCode.setCode(codes);
        return promotionMapping.convertTo(promotionCode);
    }

    @Override
    public List<PromotionVo> getPromotionCode(Long uid, Integer status, Integer type) {
        if(status == null){
            status = 0;
        }
        if(type == null){
            type = 1;
        }
        QueryWrapper<PromotionCode> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid", uid);
        queryWrapper.eq("status", status);
        queryWrapper.eq("type", type);
        List<PromotionCode> promotionCodes = baseMapper.selectList(queryWrapper);
        promotionCodes.forEach(promotionCode -> {
            String code = promotionCode.getCode();
            String token = promotionCode.getToken();
            Integer types = promotionCode.getType();
            promotionCode.setCode(code + token + types);
        });
        List<PromotionVo> promotionVos = promotionMapping.convertTo(promotionCodes);
        return promotionVos;
    }

    @Override
    public void usePromotionCode(Long uid, String codes) {
        if(codes == null) {
            throw new RuntimeException("优惠码不能为空");
        }
        if(codes != null && (codes.length() != 49 || (codes.charAt(codes.length() - 1) != '0' && codes.charAt(codes.length() - 1) != '1'))){
            throw new RuntimeException("优惠码格式错误");
        }
        String[] promotionInfo = getPromotionInfo(codes);
        String code = promotionInfo[0];
        Integer type = Integer.valueOf(promotionInfo[2]);
        RLock lock = redissonClient.getLock(PromotionConstant.PROMOTION_CODE_TOKEN_PREFIX + code);
        try{
            boolean flag = lock.tryLock();
            if(!flag){
                throw new RuntimeException("使用失败，请勿重复操作");
            }
            PromotionVo promotionVo = this.checkPromotionCode(uid, codes);
            if(promotionVo == null){
                throw new RuntimeException("优惠码不可用");
            }
            if(type == 1){
                // 更新个人优惠码状态
                QueryWrapper<PromotionCode> queryWrapper = new QueryWrapper<>();
                PromotionCode promotionCode = PromotionCode.builder()
                        .status(1).build();
                queryWrapper.eq("code", code);
                queryWrapper.eq("uid", uid);
                baseMapper.update(promotionCode, queryWrapper);
            }
        }catch (Exception e){
            log.info("出错" + e.getMessage());
            throw new RuntimeException(e.getMessage());
        }finally {
            // 释放锁
            lock.unlock();
        }
    }

//    @Transactional(rollbackFor = RuntimeException.class)
    void generatePromotionCode(Long uid, int count) {
        try{
            float discountRate = this.getDiscountRate();
            for(int i = 0; i < count; i++) {
                Date expireDate = DateUtils.addDays(new Date(), Constants.PROMOTION_EXPIRATION);
                PromotionCode promotionCode = PromotionCode.builder()
                        .code(genPromotionCode())
                        .token(genToken())
                        .discountRate(discountRate)
                        .status(0)
                        .type(1)
                        .expireTime(expireDate)
                        .uid(uid)
                        .build();
                baseMapper.insert(promotionCode);
            }
        }catch (Exception e){
            log.info("出错" + e.getMessage());
            throw new RuntimeException("优惠码生成失败");
        }

    }

    private Float getDiscountRate() {
        Random random = new Random();
        int discountRate = random.nextInt(discountRateProperties.getHigh()) + discountRateProperties.getLow();

        return discountRate / 100f;
    }


}
